<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
   
      <title>Cap&iacute;tulo 5. Fuentes de datos</title>
      <meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2">
      <link rel="home" href="indice.html" title="Manual Usuario gvHidra">
      <link rel="up" href="Parte_3.html" title="Parte&nbsp;III.&nbsp;Complementos al desarrollo">
      <link rel="prev" href="Parte_3.html" title="Parte&nbsp;III.&nbsp;Complementos al desarrollo">
      <link rel="next" href="ch05s02.html" title="5.2. Web Services">
   </head>
   <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
      <div class="navheader">
         <table width="100%" summary="Navigation header">
            <tr>
               <th colspan="3" align="center">Cap&iacute;tulo 5. Fuentes de datos</th>
            </tr>
            <tr>
               <td width="20%" align="left"><a accesskey="p" href="Parte_3.html">Anterior</a>&nbsp;
               </td>
               <th width="60%" align="center">Parte&nbsp;III.&nbsp;Complementos al desarrollo</th>
               <td width="20%" align="right">&nbsp;<a accesskey="n" href="ch05s02.html">Siguiente</a></td>
            </tr>
         </table>
         <hr>
      </div>
      <div class="chapter" title="Cap&iacute;tulo 5. Fuentes de datos">
         <div class="titlepage">
            <div>
               <div>
                  <h2 class="title"><a name="d4e3899"></a>Cap&iacute;tulo 5. Fuentes de datos
                  </h2>
               </div>
            </div>
         </div>
         <div class="toc">
            <p><b>Tabla de contenidos</b></p>
            <dl>
               <dt><span class="section"><a href="ch05.html#d4e3901">5.1. Conexiones BBDD</a></span></dt>
               <dd>
                  <dl>
                     <dt><span class="section"><a href="ch05.html#d4e3904">5.1.1. Bases de Datos accesibles por gvHidra</a></span></dt>
                     <dt><span class="section"><a href="ch05.html#d4e3919">5.1.2. Acceso y conexi&oacute;n con la Base de Datos</a></span></dt>
                     <dt><span class="section"><a href="ch05.html#d4e4018">5.1.3. Transacciones</a></span></dt>
                     <dt><span class="section"><a href="ch05.html#d4e4054">5.1.4. Procedimientos almacenados</a></span></dt>
                     <dt><span class="section"><a href="ch05.html#d4e4067">5.1.5. Recomendaciones en el uso de SQL</a></span></dt>
                  </dl>
               </dd>
               <dt><span class="section"><a href="ch05s02.html">5.2. Web Services</a></span></dt>
               <dd>
                  <dl>
                     <dt><span class="section"><a href="ch05s02.html#d4e4115">5.2.1. Web Services en PHP</a></span></dt>
                     <dt><span class="section"><a href="ch05s02.html#d4e4135">5.2.2. Generaci&oacute;n del WSDL</a></span></dt>
                     <dt><span class="section"><a href="ch05s02.html#d4e4143">5.2.3. Web Services en gvHIDRA</a></span></dt>
                  </dl>
               </dd>
               <dt><span class="section"><a href="ch05s03.html">5.3. ORM</a></span></dt>
               <dd>
                  <dl>
                     <dt><span class="section"><a href="ch05s03.html#d4e4206">5.3.1. Introducci&oacute;n</a></span></dt>
                     <dt><span class="section"><a href="ch05s03.html#d4e4227">5.3.2. Ejemplo: Propel ORM</a></span></dt>
                  </dl>
               </dd>
            </dl>
         </div>
           
         
           
         <div class="section" title="5.1. Conexiones BBDD">
            <div class="titlepage">
               <div>
                  <div>
                     <h2 class="title" style="clear: both"><a name="d4e3901"></a>5.1. Conexiones BBDD
                     </h2>
                  </div>
               </div>
            </div>
                
            
                
            <p><a name="C5BBDD"></a></p>
            
                
            <div class="section" title="5.1.1. Bases de Datos accesibles por gvHidra">
               <div class="titlepage">
                  <div>
                     <div>
                        <h3 class="title"><a name="d4e3904"></a>5.1.1. Bases de Datos accesibles por gvHidra
                        </h3>
                     </div>
                  </div>
               </div>
                     
               
                     
               <p>Una de las caracter&iacute;sticas importantes que tenemos en PHP es la
                  gran cantidad de distintos tipos de bases de datos soportados. Cada una
                  de ellas requiere de una extensi&oacute;n que define su propia API para
                  realizar la misma tarea, desde establecer una conexi&oacute;n hasta usar
                  sentencias preparadas o control de errores. Cambiar las llamadas a la
                  API cuando cambiamos de BD en una aplicaci&oacute;n es costoso pero se puede
                  hacer, aunque en el caso de un framework no es factible porque tiene que
                        funcionar el mismo c&oacute;digo con varias BD. Lo que se suele hacer es a&ntilde;adir
                        una capa de abstracci&oacute;n que nos permita operar de la misma manera con
                        todos los tipos de BD (al menos para las operaciones m&aacute;s habituales o
                        las m&aacute;s estandarizadas). En el caso de gvHIDRA se utiliza la librer&iacute;a
                        MDB2 de PEAR (http://pear.php.net/package/MDB2/ ), una de las m&aacute;s usadas
                        para este fin gracias a su amplia funcionalidad y a la actividad del
                        proyecto. De esta forma podemos usar una BD sin preocuparnos por el
                        tipo, ya que tenemos una API &uacute;nica.
               </p>
               
                     
               <p>Sin embargo, a pesar de usar la capa de abstracci&oacute;n, sigue
                        habiendo aspectos que dependen del tipo de BD: uso de caracter&iacute;sticas
                        especiales (secuencias, limit, bloqueos, ...), manejo de transacciones,
                        representaci&oacute;n de fechas y n&uacute;meros, ... Para resolver estos problemas,
                        definimos en el framework otra capa de abstracci&oacute;n (que se implementa en
                        unas clases que se ven en el apartado siguiente) y las funciones m&aacute;s
                        importantes que realizan son:
               </p>
               
                     
               <div class="itemizedlist">
                  <ul class="itemizedlist" type="disc">
                     <li class="listitem">
                                  
                        <p>Definici&oacute;n del formato de fechas y n&uacute;meros que se va a usar
                                     para comunicarse con el gestor de BD. Este formato es transparente
                                     para el programador, ya que es el framework el que hace las
                                     conversiones necesarias cuando enviamos/recogemos informaci&oacute;n a/de
                                     la BD. Normalmente nos referiremos a &eacute;ste como <span class="bold"><strong>formato de BD</strong></span>.
                        </p>
                                
                     </li>
                     <li class="listitem">
                                  
                        <p>Inicializaci&oacute;n de la conexi&oacute;n: son operaciones que se hacen
                                     cada vez que se hace una nueva conexi&oacute;n. Por ejemplo se fija la
                                     codificaci&oacute;n que se va a usar en la comunicaci&oacute;n (actualmente LATIN1
                                     o ISO-8859-1, que es la usada en el framework), o se modifican
                                     par&aacute;metros de la conexi&oacute;n para establecer el formato de BD.
                        </p>
                                
                     </li>
                     <li class="listitem">
                                  
                        <p>Ajustes por sintaxis: aqu&iacute; se incluyen una serie de m&eacute;todos
                                     para obtener la sintaxis de ciertas operaciones que se pueden
                                     comportar de forma distinta en cada BD. Por ejemplo la clausula
                                     limit (para paginar resultados de consultas), funci&oacute;n para
                                     concatenar cadenas, uso de secuencias, ...
                        </p>
                                
                     </li>
                     <li class="listitem">
                                  
                        <p>Unificar tratamiento de errores: por ejemplo, cuando hay un
                                     registro bloqueado, poderlo detectar independientemente de la
                                     BD.
                        </p>
                                
                     </li>
                  </ul>
               </div>
               
                     
               <p>Actualmente las BD soportadas por gvHIDRA son postgresql, mysql y
                        oracle. Conforme vayamos soportando nuevos tipos (entre los soportados
                        por MDB2), la funcionalidad de esta capa se podr&aacute; ir aumentando.
               </p>
                   
            </div>
            
                
            <div class="section" title="5.1.2. Acceso y conexi&oacute;n con la Base de Datos">
               <div class="titlepage">
                  <div>
                     <div>
                        <h3 class="title"><a name="d4e3919"></a>5.1.2. Acceso y conexi&oacute;n con la Base de Datos
                        </h3>
                     </div>
                  </div>
               </div>
                     
               
                     
               <p>C&oacute;mo crear conexiones a distintas fuentes de datos.</p>
               
                     
               <div class="section" title="5.1.2.1. Introducci&oacute;n">
                  <div class="titlepage">
                     <div>
                        <div>
                           <h4 class="title"><a name="d4e3922"></a>5.1.2.1. Introducci&oacute;n
                           </h4>
                        </div>
                     </div>
                  </div>
                          
                  
                          
                  <p>El framework ofrece una serie de facilidades al programador que
                             pueden llegar a ocultar las posibilidades que tiene de conexi&oacute;n a
                             BBDD. Concretamente, tanto el pattern gvHidraForm_DB o el debug
                             (IgepDebug), son ejemplos de uso de conexiones de forma transparente
                             para el programador. En ambos casos, gvHidra se encarga de conectar
                             con el SGBD correspondiente y operar con &eacute;l, dejando una serie de
                             m&eacute;todos que para consultar/operar.
                  </p>
                  
                          
                  <p>Evidentemente, puede que nos encontremos con circunstancias que
                             nos obliguen a utilizar algo m&aacute;s de lo que hemos expuesto. Para cubrir
                             todo ello, el framework ofrece la clase IgepConexion que, a trav&eacute;s de
                             la librer&iacute;a PEAR::MDB2 conecta con diferentes SGBD. Esto permite crear
                             conexiones a diferentes fuentes de forma homogenea e independiz&aacute;rnos
                             de los drivers nativos que trabajan por debajo.
                  </p>
                  
                          
                  <p>A esta capa de abstracci&oacute;n, el framework aporta una serie de
                             perfiles de SGBD (IgepDBMS) que nos permiten configurar dichas
                             conexiones para, por ejemplo, independizar el formato de la
                             configuraci&oacute;n del SGBD. Actualmente se han definido los siguientes
                             perfiles:
                  </p>
                  
                          
                  <div class="table"><a name="d4e3927"></a><p class="title"><b>Tabla 5.1. Perfiles SGBD</b></p>
                     <div class="table-contents">
                                  
                        
                                  
                        <table summary="Perfiles SGBD" border="1">
                           <colgroup>
                              <col width="75" align="center">
                              <col width="120" align="center">
                           </colgroup>
                           <thead>
                              <tr>
                                 <th align="center">SGBD</th>
                                 <th align="center">PERFIL (CLASE)</th>
                              </tr>
                           </thead>
                           <tbody>
                              <tr>
                                 <td align="left">Oracle</td>
                                 <td align="left">IgepDBMS_oci8.php</td>
                              </tr>
                              <tr>
                                 <td align="left">PostgreSql</td>
                                 <td align="left">IgepDBMS_pgsql.php</td>
                              </tr>
                              <tr>
                                 <td align="left">MySQL</td>
                                 <td align="left">IgepDBMS_mysql.php</td>
                              </tr>
                           </tbody>
                        </table>
                                
                     </div>
                  </div><br class="table-break">
                  
                          
                  <div class="note" title="Nota" style="margin-left: 0.5in; margin-right: 0.5in;">
                     <h3 class="title">Nota</h3>
                               
                     <p>se pueden crear perfiles para otros SGBD de forma
                                  sencilla.
                     </p>
                             
                  </div>
                        
               </div>
               
                     
               <div class="section" title="5.1.2.2. Creaci&oacute;n de una conexi&oacute;n">
                  <div class="titlepage">
                     <div>
                        <div>
                           <h4 class="title"><a name="d4e3948"></a>5.1.2.2. Creaci&oacute;n de una conexi&oacute;n
                           </h4>
                        </div>
                     </div>
                  </div>
                          
                  
                          
                  <p>Para crear una conexi&oacute;n a una base de datos simplemente tenemos
                             que crear una instancia de la clase IgepConexion pas&aacute;ndole el dsn de
                             conexi&oacute;n a dicha BBDD. Dicho dsn tiene que tener la siguiente
                             estructura (en PHP):
                  </p>
                  
                          
                  <div class="informalexample">
                               
                     
                               <pre class="programlisting">//Ejemplo postgresql
$dsnPos = array(
    'phptype'  =&gt; 'pgsql',
    'username' =&gt; 'xxxx',
    'password' =&gt; 'xxxx',
    'hostspec' =&gt; 'xxxx',
    'database' =&gt; 'xxxx',
);            

//Ejemplo oracle
$dsnOra = array(
    'phptype'  =&gt; 'oci8',
    'username' =&gt; 'xxxx',
    'password' =&gt; 'xxxx',
    'hostspec' =&gt; 'xxxx',
);</pre>
                             </div>
                  
                          
                  <p>Estos dsn se tienen que definir en el fichero de configuraci&oacute;n
                             de la aplicaci&oacute;n gvHidraConfig.inc.xml siguiendo la sintaxis que
                             especifica su DTD. Tambi&eacute;n se pueden definir en la carga din&aacute;mica,
                             aunque es poco recomendable.
                  </p>
                  
                          
                  <p>La construcci&oacute;n de la conexi&oacute;n ser&iacute;a tan simple como:</p>
                  
                          
                  <div class="informalexample">
                               
                     
                               <pre class="programlisting">//Nueva conexion a postgresql
$conPos = new IgepConexion($dsnPos);

//Nueva conexion a oracle
$conOra = new IgepConexion($dsnOra);</pre>
                             </div>
                  
                          
                  <p>Despu&eacute;s de crear la instancia, hay que comprobar si ha habido
                             problemas de conexi&oacute;n:
                  </p>
                  
                          
                  <div class="informalexample">
                               
                     
                               <pre class="programlisting">if (PEAR::isError($conPos-&gt;getPEARConnection()))
     return;</pre>
                             </div>
                  
                          
                  <p><span class="bold"><strong>&iquest;Conexiones
                                   persistentes?</strong></span></p>
                  
                          
                  <p>Si, conexiones persistentes aunque con matizaciones. El driver
                             nativo de PHP para PostgreSQL ofrece la posibilidad de, con el objeto
                             de optimizar, reutilizar las conexiones. De modo que, si creamos 10
                             conexiones, realmente tenemos 10 referencias a la misma conexi&oacute;n. Esto
                             aumenta el rendimiento ya que s&oacute;lo tenemos un "coste" de conexi&oacute;n
                             aunque, evidentemente es peligroso. Por ello el framework, por
                             defecto, crea conexiones independientes que mueren cuando el
                             programador destruye el objeto (o cuando acaba el hilo de
                             ejecuci&oacute;n).
                  </p>
                  
                          
                  <p>Puede que, en algunos casos puntuales, se quiera utilizar este
                             tipo de conexiones (s&oacute;lo funcionar&iacute;an en PostgreSQL), y para esos
                             casos se ha creado un par&aacute;metro en el constructor de la conexion
                             (bool). Este par&aacute;metro, persistent, indica si el programador quiere
                             solicitar una conexion persistente, siendo su valor por defecto
                             false.
                  </p>
                  
                          
                  <div class="informalexample">
                               
                     
                               <pre class="programlisting">//Conexion permanente (reusable/reusada)
$pcon = new IgepConexion($dsn_log,true);</pre>
                             </div>
                        
               </div>
               
                     
               <div class="section" title="5.1.2.3. Utilizar conexi&oacute;n de la clase manejadora (gvHidraForm_DB)">
                  <div class="titlepage">
                     <div>
                        <div>
                           <h4 class="title"><a name="d4e3966"></a>5.1.2.3. Utilizar conexi&oacute;n de la clase manejadora
                                      (gvHidraForm_DB)
                           </h4>
                        </div>
                     </div>
                  </div>
                          
                  
                          
                  <p>Puede que en ciertas circunstancias nosotros queramos
                             recuperar/utilizar la conexi&oacute;n que mantiene autom&aacute;ticamente la clase
                             manejadora (las que extienden de gvHidraForm_DB). Para ello, se
                             facilita el m&eacute;todo getConnection que devuelve la instancia de la
                             conexi&oacute;n en uso.
                  </p>
                  
                          
                  <div class="informalexample">
                               
                     
                               <pre class="programlisting">//En la clase manejadora
$con = $this-&gt;getConnection();</pre>
                             </div>
                  
                          
                  <div class="note" title="Nota" style="margin-left: 0.5in; margin-right: 0.5in;">
                     <h3 class="title">Nota</h3>
                               
                     <p>la clase manejadora ofrece tambi&eacute;n los m&eacute;todos consultar y
                                  operar sobre esta conexi&oacute;n para poder lanzarlos sin recuperar la
                                  instancia de la conexi&oacute;n.
                     </p>
                             
                  </div>
                        
               </div>
               
                     
               <div class="section" title="5.1.2.4. M&eacute;todos de conexi&oacute;n">
                  <div class="titlepage">
                     <div>
                        <div>
                           <h4 class="title"><a name="d4e3973"></a>5.1.2.4. M&eacute;todos de conexi&oacute;n
                           </h4>
                        </div>
                     </div>
                  </div>
                          
                  
                          
                  <p>En este apartado vamos a ver algunos de los m&eacute;todos interesantes
                             que ofrece la clase de conexiones de gvHIDRA. No los vermos todos
                             (para ello consultar PHPDoc o doxy), pero si los m&aacute;s &uacute;tiles.
                  </p>
                  
                          
                  <div class="section" title="5.1.2.4.1. consultar">
                     <div class="titlepage">
                        <div>
                           <div>
                              <h5 class="title"><a name="d4e3976"></a>5.1.2.4.1. consultar
                              </h5>
                           </div>
                        </div>
                     </div>
                               
                     
                               
                     <p>Este m&eacute;todo sirve para realizar una query con la conexi&oacute;n
                                  activa. El primer par&aacute;metro corresponde a la SELECT que queremos
                                  ejecutar. Opcionalmente podemos pasarle un segundo par&aacute;metro
                                  indicando si queremos que transforme los datos (especialmente fechas
                                  y n&uacute;meros) al formato interno del framework. Sino se especifica este
                                  segundo par&aacute;metro, los datos vendr&aacute;n en el formato configurado para
                                  cada SGBD, por lo que puede que no sean adecuados para operar con
                                  ellos.
                     </p>
                     
                               
                     <div class="informalexample">
                                    
                        
                                    <pre class="programlisting">// obtenemos datos para operar en capa de negocio (FW)
$res=$con-&gt;consultar(" SELECT fecha_ini,fecha_fin
         		 FROM tper_permisos
         		 WHERE nregpgv = '44908412R'", 
                     array( 'DATATYPES'=&gt;array('fecha_ini'=&gt;TIPO_FECHA,'fecha_fin'=&gt;TIPO_FECHA,)));
</pre>
                                  </div>
                             
                  </div>
                  
                          
                  <div class="section" title="5.1.2.4.2. operar">
                     <div class="titlepage">
                        <div>
                           <div>
                              <h5 class="title"><a name="d4e3981"></a>5.1.2.4.2. operar
                              </h5>
                           </div>
                        </div>
                     </div>
                               
                     
                               
                     <p>Este m&eacute;todo sirve para lanzar operaciones DML m&aacute;s all&aacute; del
                                  comando SELECT; es decir UPDATE,INSERT o DELETE. En ocasiones
                                  necesita que se ejecute sobre los datos el m&eacute;todo
                                  prepararOperacion.
                     </p>
                             
                  </div>
                  
                          
                  <div class="section" title="5.1.2.4.3. prepararOperacion">
                     <div class="titlepage">
                        <div>
                           <div>
                              <h5 class="title"><a name="d4e3984"></a>5.1.2.4.3. prepararOperacion
                              </h5>
                           </div>
                        </div>
                     </div>
                               
                     
                               
                     <p>Convierte los campos al formato que acepta la base de datos
                                  (escapar los car&aacute;cteres especiales en textos, ajustar los
                                  separadores decimales y de grupos en n&uacute;meros y formatos en fechas).
                                  Hay que llamarla antes del m&eacute;todo consultar, operar o preparedQuery.
                                  Los par&aacute;metros que acepta son:
                     </p>
                     
                               
                     <div class="orderedlist">
                        <ol class="orderedlist" type="1">
                           <li class="listitem">
                                            
                              <p>valor: puede ser un valor simple o un array de registros,
                                               donde cada registro es un array con estructura
                                               'campo'=&gt;valor. Es un par&aacute;metro por referencia, por lo que
                                               devuelve el resultado en esta variable.
                              </p>
                                          
                           </li>
                           <li class="listitem">
                                            
                              <p>tipo: si el valor es simple indicaremos directamente el
                                               tipo que puede ser las constantes: TIPO_CARACTER, TIPO_ENTERO,
                                               TIPO_DECIMAL, TIPO_FECHA y TIPO_FECHAHORA. Si el valor es un
                                               array, el tipo contiene un array asociativo con los tipos de
                                               cada columna. M&aacute;s adelante se puede ver un ejemplo con valor
                                               simple, y &eacute;ste seria un ejemplo con array:
                              </p>
                              
                                            
                              <div class="informalexample">
                                                 
                                 
                                                 <pre class="programlisting">$datos = array( array('nombre'=&gt;"L'Eliana", 'superficie'=&gt;'45.6') );
$conexion-&gt;prepararOperacion($datos, array('nombre'=&gt;array('tipo'=&gt;TIPO_CARACTER,), 'superficie'=&gt;array('tipo'=&gt;TIPO_DECIMAL,),));
// en $datos ya tenemos los datos transformados</pre>
                                               </div>
                                          
                           </li>
                        </ol>
                     </div>
                             
                  </div>
                  
                          
                  <div class="section" title="5.1.2.4.4. CalcularSecuenciaBD">
                     <div class="titlepage">
                        <div>
                           <div>
                              <h5 class="title"><a name="d4e3994"></a>5.1.2.4.4. CalcularSecuenciaBD
                              </h5>
                           </div>
                        </div>
                     </div>
                               
                     
                               
                     <p>Calcula el valor de una secuencia de BD. Consulte en el manual
                                  de su SGBD las opciones que ofrece al respecto.
                     </p>
                             
                  </div>
                  
                          
                  <div class="section" title="5.1.2.4.5. CalcularSecuencia">
                     <div class="titlepage">
                        <div>
                           <div>
                              <h5 class="title"><a name="d4e3997"></a>5.1.2.4.5. CalcularSecuencia
                              </h5>
                           </div>
                        </div>
                     </div>
                               
                     
                               
                     <p>Calcula el m&aacute;ximo de una tabla siguiendo varios criterios
                                  (seg&uacute;n los par&aacute;metros).
                     </p>
                             
                  </div>
                  
                          
                  <div class="section" title="5.1.2.4.6. preparedQuery">
                     <div class="titlepage">
                        <div>
                           <div>
                              <h5 class="title"><a name="d4e4000"></a>5.1.2.4.6. preparedQuery
                              </h5>
                           </div>
                        </div>
                     </div>
                               
                     
                               
                     <p>Es similar a consultar y operar, pero usando sentencias
                                  preparadas. Es m&aacute;s eficiente que estar formando cada vez la
                                  sentencia SQL ya que el SGBD solo tiene que analizar la sentencia la
                                  primera vez. No requiere escapar caracteres especiales. Es
                                  recomendable especialmente cuando usamos la sentencia dentro de
                                  bucles. Al igual que consultar, tambi&eacute;n tiene un par&aacute;metro opcional,
                                  que permite pasarle los tipos de los campos. El &uacute;ltimo par&aacute;metro
                                  tambi&eacute;n es opcional y sirve para conservar la sentencia preparada
                                  cuando ejecutamos la misma sentencia varias veces con distintos
                                  par&aacute;metros.
                     </p>
                     
                               
                     <p>A continuaci&oacute;n ponemos un ejemplo de utilizaci&oacute;n. Comprobamos
                                  que, dadas las facturas del a&ntilde;o 2006, todas sus l&iacute;neas esten en
                                  estado 'REVISADA', y si no es as&iacute; actualizamos la factura en
                                  concreto pas&aacute;ndola a estado 'SINREVISION' y le a&ntilde;adiremos el campo
                                  observaciones que ha introducido el usuario.
                     </p>
                     
                               
                     <div class="informalexample">
                                    
                        
                                    <pre class="programlisting">$conexion = new IgepConexion($dsn);
$sel = "SELECT nfactura as \"nfactura\" FROM lineas WHERE anyo='".2005."' AND estado&lt;&gt;'REVISADA' group by nfactura";
$res = $conexion-&gt;consultar($sel);
if ($res!=-1 and count($res[0])&gt;0) {
   //Como no sabemos el contenido de observaciones escapamos por si hay cualquier caracter problematico
   $conexion-&gt;prepararOperacion($observaciones, TIPO_CARACTER);
   foreach ($res as $facturaSinRevision){
      $res2 = $conexion-&gt;operar("UPDATE factura set observaciones='$observaciones', estado='SINREVISION' 
                                WHERE anyo='2005' AND factura='".$facturaSinRevision['nfactura']."'");
      if ($res2==-1) {
         // Mensaje de Error
         ....
      }
}
</pre>
                                  </div>
                     
                               
                     <p>El mismo ejemplo usando sentencias preparadas seria:</p>
                     
                               
                     <div class="informalexample">
                                    
                        
                                    <pre class="programlisting">$conexion = new IgepConexion($dsn);
try {
   $sel = "SELECT nfactura as \"nfactura\" FROM lineas WHERE anyo=? AND estado&lt;&gt;'REVISADA' group by nfactura";
   $res = $conexion-&gt;preparedQuery($sel, false, array(2005));
   if (count($res[0])&gt;0) {
      $upd = null;
      $sql = "UPDATE factura set observaciones=?, estado='SINREVISION' WHERE anyo=? AND factura=?";
      //con sentencias preparadas no es necesario escapar caracteres especiales
      foreach ($res as $facturaSinRevision)
         $res2 = $conexion-&gt;preparedQuery($sql, true, array($observaciones,'2005',$facturaSinRevision['nfactura']), null, $upd);
   }
} catch (Exception $e) {
   // Mensaje de Error
   ...
}
</pre>
                                  </div>
                     
                               
                     <p>El control de errores con sentencias preparadas siempre es a
                                  trav&eacute;s de <a class="ulink" href="http://zope.coput.gva.es/proyectos/igep/trabajo/igep/excepciones.html" target="_top">excepciones</a>.
                     </p>
                     
                               
                     <p>Tambi&eacute;n est&aacute;n disponibles los m&eacute;todos consultarForUpdate y
                                  preparedQueryForUpdate que permiten bloquear los registros que
                                  recuperan. M&aacute;s informaci&oacute;n <a class="ulink" href="http://zope.coput.gva.es/proyectos/igep/trabajo/igep/trans.html" target="_top">aqu&iacute;</a>.
                     </p>
                             
                  </div>
                        
               </div>
               
                     
               <div class="section" title="5.1.2.5. Utilizar el driver MDB2 o nativo">
                  <div class="titlepage">
                     <div>
                        <div>
                           <h4 class="title"><a name="d4e4013"></a>5.1.2.5. Utilizar el driver MDB2 o nativo
                           </h4>
                        </div>
                     </div>
                  </div>
                          
                  
                          
                  <p>En algunos casos, puede ser interesante trabajar directamente
                             con el driver PEAR::MDB2 o el driver nativo de PHP. Un ejemplo puede
                             ser la utilizaci&oacute;n de procedimientos almacenados. Para estos casos el
                             FW ofrece el m&eacute;todo getPEARConnection que devuelve el objeto
                             PEAR::MDB2 conectado
                  </p>
                  
                          
                  <div class="informalexample">
                               
                     
                               <pre class="programlisting">/*CONEXION ACTIVA DE LA CLASE MANEJADORA*/
//Recogemos el objeto IgepConexion de la conexion activa.
$conPEARMDB2 = $this-&gt;getConnection();
//Recogemos el objeto PEAR::MDB2 de la conexion activa.
$conPEARMDB2 = $this-&gt;getConnection()-&gt;getPEARConnection();
//Recogemos el driver nativo de PHP de la conexion activa.
$conPHP = $this-&gt;getConnection()-&gt;getPEARConnection()-&gt;getConnection();

/*NUEVA CONEXION*/
//Recogemos el objeto PEAR::MDB2
$this-&gt;_conOracle = new IgepConexion($g_dns_ora);
$conPEARMDB2 = $this-&gt;_conOracle-&gt;getPEARConnection();
//Recogemos el driver nativo de PHP
$conPHP = $this-&gt;_conOracle-&gt;getPEARConnection()-&gt;getConnection();
</pre>
                             </div>
                        
               </div>
                   
            </div>
            
                
            <div class="section" title="5.1.3. Transacciones">
               <div class="titlepage">
                  <div>
                     <div>
                        <h3 class="title"><a name="d4e4018"></a>5.1.3. Transacciones
                        </h3>
                     </div>
                  </div>
               </div>
                     
               
                     
               <p></p>
               
                     
               <div class="section" title="5.1.3.1. Introducci&oacute;n">
                  <div class="titlepage">
                     <div>
                        <div>
                           <h4 class="title"><a name="d4e4021"></a>5.1.3.1. Introducci&oacute;n
                           </h4>
                        </div>
                     </div>
                  </div>
                          
                  
                          
                  <p>Actualmente el framework no fija el par&aacute;metro autocommit, por lo
                             que estamos usando el valor fijado en los servidores: activado para
                             postgres y mysql, y desactivado para oracle (de hecho, no se puede
                             activar). En pr&oacute;ximas versiones se normalizar&aacute; esta situaci&oacute;n. Cuando
                             queramos englobar varias operaciones en una transacci&oacute;n, tendremos que
                             iniciar una transacci&oacute;n o asegurarnos que ya estamos en una. De
                             momento no hay soporte para transacciones anidadas.
                  </p>
                  
                          
                  <div class="note" title="Nota" style="margin-left: 0.5in; margin-right: 0.5in;">
                     <h3 class="title">Nota</h3>
                               
                     <p>En mysql, para tener soporte transaccional hay que definir las
                                  tablas con storages que lo soporten como InnoDB.
                     </p>
                             
                  </div>
                  
                          
                  <p>El framework inicia una transaccion automaticamente para hacer
                             las operaciones del CRUD. Para el resto de casos, deberemos iniciar
                             &eacute;sta de modo expl&iacute;cito. Se puede hacer con el m&eacute;todo <span class="bold"><strong>empezarTransaccion</strong></span> de IgepConexion. En las
                             clases de negocio no hace falta hacerlo (ya que el framework inicia la
                             transacci&oacute;n), a menos que queramos que la transacci&oacute;n empiece en
                             preInsertar, preModificar o preBorrar.
                  </p>
                  
                          
                  <p>Ejemplo:</p>
                  
                          
                  <div class="informalexample">
                               
                     
                               <pre class="programlisting">$this-&gt;getConnection()-&gt;empezarTransaccion();</pre>
                             </div>
                  
                          
                  <p>Tambi&eacute;n es habitual empezar una transacci&oacute;n cuando tenemos una
                             conexi&oacute;n sobre un DSN distinto al empleado en el formulario, sobre el
                             que queremos hacer operaciones de actualizaci&oacute;n.
                  </p>
                  
                          
                  <p>La transacci&oacute;n acaba con el m&eacute;todo <span class="bold"><strong>acabarTransaccion</strong></span>, y recibe un par&aacute;metro
                             booleano indicando si ha habido error, y en funci&oacute;n de &eacute;ste se hace un
                             commit o rollback. No hay que llamarlo cuando se trata de la
                             transacci&oacute;n del framework.
                  </p>
                        
               </div>
               
                     
               <div class="section" title="5.1.3.2. Control de Concurrencia">
                  <div class="titlepage">
                     <div>
                        <div>
                           <h4 class="title"><a name="d4e4034"></a>5.1.3.2. Control de Concurrencia
                           </h4>
                        </div>
                     </div>
                  </div>
                          
                  
                          
                  <p>Para las operaciones del CRUD, el framework aplica un m&eacute;todo
                             simple para evitar que dos usuarios modifiquen simult&aacute;neamente un
                             registro que previamente han le&iacute;do. Consiste en a&ntilde;adir a la condici&oacute;n
                             del where, en los update y delete, todos los campos modificables de la
                             tabla con los valores le&iacute;dos previamente. Si el registro no se
                             encuentra significa que otro usuario lo ha modificado, y entonces se
                             obliga al usuario a repetir la operaci&oacute;n.
                  </p>
                  
                          
                  <p>Esta aproximaci&oacute;n tambi&eacute;n puede usarse en otros casos, aunque
                             cuando la transacci&oacute;n incluye muchas operaciones, puede ser muy
                             complejo. Para estas situaciones, tambi&eacute;n se puede usar la opci&oacute;n de
                             bloquear los registros, como se explica a continuaci&oacute;n.
                  </p>
                  
                          
                  <div class="section" title="5.1.3.2.1. Bloqueos">
                     <div class="titlepage">
                        <div>
                           <div>
                              <h5 class="title"><a name="d4e4038"></a>5.1.3.2.1. Bloqueos
                              </h5>
                           </div>
                        </div>
                     </div>
                               
                     
                               
                     <p>Las operaciones DML update y delete bloquean impl&iacute;citamente
                                  los registros afectados. Sin embargo hay ocasiones en las que
                                  primero leemos informaci&oacute;n de la BD, y en funci&oacute;n de ella
                                  actualizamos otra informaci&oacute;n. Ejemplos de estos casos son al
                                  incrementar un saldo, obtener un numero secuencial, ... Para estas
                                  situaciones nos interesa bloquear los registros que leemos, y as&iacute;
                                  nos aseguramos que no van a cambiar mientras hacemos la
                                  actualizaci&oacute;n.
                     </p>
                     
                               
                     <p>En las conexiones con autocommit, hay que tener la precauci&oacute;n
                                  de empezar una transacci&oacute;n antes de hacer los bloqueos (o
                                  asegurarnos que estamos en una transacci&oacute;n ya empezada). Los
                                  bloqueos se liberan cuando la transacci&oacute;n finaliza. Tambi&eacute;n hay que
                                  recordar que al finalizar cada petici&oacute;n al servidor, se cierran las
                                  conexiones con las bases de datos, y por tanto tambi&eacute;n se liberan
                                  todos los bloqueos. Eso significa que por ejemplo, no podemos
                                  mantener bloqueado un registro mientras el usuario lo edita.
                     </p>
                     
                               
                     <p>Los bloqueos se hacen sin espera (si el registro est&aacute;
                                  bloqueado por otro usuario se produce un error), con el fin de no
                                  colapsar el servidor web. En el caso de mysql no se dispone de la
                                  opci&oacute;n de no esperar, aunque la espera se corta tras un timeout.
                                  Este timeout por defecto es de 50 segundos, por lo que conviene
                                  cambiar el par&aacute;metro innodb_lock_wait_timeout a un valor de menos de
                                  5 segundos.
                     </p>
                     
                               
                     <p>Para hacer estos bloqueos, tenemos en IgepConexion el m&eacute;todo
                                  <span class="bold"><strong>consultarForUpdate</strong></span> que funciona
                                  exactamente como consultar pero bloqueando los registros afectados.
                                  Si alg&uacute;n registro ya esta bloqueado por otro usuario, se produce una
                                  excepci&oacute;n que habr&aacute; que capturar. A continuaci&oacute;n tenemos un ejemplo
                                  de su utilizaci&oacute;n:
                     </p>
                     
                               
                     <div class="informalexample">
                                    
                        
                                    <pre class="programlisting">$con-&gt;empezarTransaccion();
try {
   $res = $con-&gt;consultarForUpdate('select * from tinv_donantes where orden=5');
   if ($res == -1) {
      $this-&gt;showMensaje('APL-x'); // algun problema con la consulta
      $con-&gt;acabarTransaccion(1);
      return -1;
   }
} catch (gvHidraLockException $e) {
   $this-&gt;showMensaje('APL-y'); // algun registro bloqueado
   $con-&gt;acabarTransaccion(1);
   return -1;
}
// actualizaciones varias relacionadas con el registro que tenemos bloqueado
//...
$con-&gt;acabarTransaccion(0);
</pre>
                                  </div>
                     
                               
                     <p>Tambi&eacute;n podemos hacer lo mismo usando el m&eacute;todo <span class="bold"><strong>preparedQueryForUpdate</strong></span>, que funciona similar
                                  pero usando sentencias preparadas:
                     </p>
                     
                               
                     <div class="informalexample">
                                    
                        
                                    <pre class="programlisting">$con-&gt;empezarTransaccion();
try {
   $res = $con-&gt;preparedQueryForUpdate('select * from tinv_donantes where orden=?', array(5,));
} catch (gvHidraLockException $e) {
   $this-&gt;showMensaje('APL-x'); // algun registro bloqueado
   $con-&gt;acabarTransaccion(1);
   return -1;
} catch (gvHidraSQLException $e) {
   $this-&gt;showMensaje('APL-y'); // algun problema con la consulta; con $e-&gt;getSqlerror() obtenemos error PEAR
   $con-&gt;acabarTransaccion(1);
   return -1;
}
// actualizaciones varias relacionadas con el registro que tenemos bloqueado
//...
$con-&gt;acabarTransaccion(0);</pre>
                                  </div>
                     
                               
                     <p>En el <a class="link" href="ch07.html#C7Excepciones">cap&iacute;tulo 7</a> se
                                  explican con m&aacute;s detalle las excepciones que se pueden
                                  utilizar.
                     </p>
                     
                               
                     <p>En la consulta usada para bloquear conviene limitar al m&aacute;ximo
                                  el numero de registros obtenidos a los estrictamente necesarios, y
                                  no emplear joins ya que se bloquear&iacute;an los registros afectados de
                                  todas las tablas. De esta manera aumentamos el nivel de concurrencia
                                  y reducimos la posibilidad de error por registros bloqueados.
                     </p>
                             
                  </div>
                        
               </div>
                   
            </div>
            
                
            <div class="section" title="5.1.4. Procedimientos almacenados">
               <div class="titlepage">
                  <div>
                     <div>
                        <h3 class="title"><a name="d4e4054"></a>5.1.4. Procedimientos almacenados
                        </h3>
                     </div>
                  </div>
               </div>
                     
               
                     
               <p>En este apartado intentaremos explicar como utilizar
                        procedimientos almacenados en gvHIDRA
               </p>
               
                     
               <div class="section" title="5.1.4.1. Introducci&oacute;n">
                  <div class="titlepage">
                     <div>
                        <div>
                           <h4 class="title"><a name="d4e4057"></a>5.1.4.1. Introducci&oacute;n
                           </h4>
                        </div>
                     </div>
                  </div>
                          
                  
                          
                  <p>Puede que nuestro sistema de informaci&oacute;n se haya dise&ntilde;ado
                             depositando toda la l&oacute;gica de la aplicaci&oacute;n en procedimientos
                             almacenados o que, puntualmente, tengamos la necesidad de acceder a
                             uno de esos recursos del SGBD. Para ellos, en este apartado daremos
                             algunos ejemplos de como hacerlo a trav&eacute;s de las conexiones del
                             FW.
                  </p>
                        
               </div>
               
                     
               <div class="section" title="5.1.4.2. Creaci&oacute;n de una conexi&oacute;n">
                  <div class="titlepage">
                     <div>
                        <div>
                           <h4 class="title"><a name="d4e4060"></a>5.1.4.2. Creaci&oacute;n de una conexi&oacute;n
                           </h4>
                        </div>
                     </div>
                  </div>
                          
                  
                          
                  <p>Las conexiones al framework est&aacute;n organizadas en tres capas
                             (capa DBMS-gvHIDRA, capa MDB2 y driver nativo PHP). Las llamadas a
                             procedimientos almacenados se pueden realizar desde cualquier a de las
                             capas, pero ganamos en versatilidad a medida que nos acercamos al
                             driver nativo.
                  </p>
                  
                          
                  <p>La capa DBMS-gvHIDRA actualmente s&oacute;lo te permite trabajar
                             mediante el m&eacute;todo operar, lo cual, excepto para casos muy puntuales,
                             no parece c&oacute;modo. La capa MDB2 tiene m&eacute;todos como el <span class="bold"><strong>executeStoredProc</strong></span> especialmente para estos
                             casos. De todos modos, nuestra recomendaci&oacute;n es utilizar el driver
                             nativo ya que parece que en los dos casos anteriores no se trabaja
                             bien con valores entrada/salida.
                  </p>
                  
                          
                  <div class="informalexample">
                               
                     
                               <pre class="programlisting">$conexion = new IgepConexion($dsn);
$con = $conexion-&gt;getPEARConnection()-&gt;getConnection();
$query="begin proced('1234', :retorno, :msgproc); end;";
$id_result= @OCIParse( $con, $query);
if (!id_result or OCIError($id_result))
        return;
OCIBindByName ( $id_result, ":retorno", $ret, 10 );
OCIBindByName ( $id_result, ":msgproc", $msg, 200 );
@OCIExecute ( $id_result, OCI_DEFAULT );//ATENCION A partir de PHP 5.3.2 cambiar OCI_DEFAULT por OCI_NO_AUTO_COMMIT
</pre>
                             </div>
                        
               </div>
                   
            </div>
            
                
            <div class="section" title="5.1.5. Recomendaciones en el uso de SQL">
               <div class="titlepage">
                  <div>
                     <div>
                        <h3 class="title"><a name="d4e4067"></a>5.1.5. Recomendaciones en el uso de SQL
                        </h3>
                     </div>
                  </div>
               </div>
                     
               
                     
               <p>En este documento se dan algunas recomendaciones para que las
                        sentencias SQL usadas en gvHidra sean lo m&aacute;s est&aacute;ndar posible, y
                        minimizar el impacto de un posible cambio de gestor de base de datos
                        (SGBD). Los SGBD considerados son PostgreSQL, Oracle y Mysql.
               </p>
               
                     
               <div class="section" title="5.1.5.1. Alias en las columnas">
                  <div class="titlepage">
                     <div>
                        <div>
                           <h4 class="title"><a name="d4e4070"></a>5.1.5.1. Alias en las columnas
                           </h4>
                        </div>
                     </div>
                  </div>
                          
                  
                          
                  <p>Se recomienda poner siempre alias en los campos de una
                             consulta.
                  </p>
                  
                          
                  <p>Si no usamos los alias, en oracle los nombres de las columnas
                             siempre saldr&aacute;n en may&uacute;sculas, con lo que no funcionar&aacute; si cambiamos o
                             otro SGBD. En PEAR::MDB2 hay una opci&oacute;n de compatibilidad que
                             transforma todo a min&uacute;scula, pero como no permite tener
                             identificadores mixtos (del tipo 'NombreProveedor'), se ha optado por
                             no habilitarla. Para que el alias tenga efecto hay que ponerlo con
                             comillas dobles:
                  </p>
                  
                          
                  <div class="informalexample">
                               
                     
                               <pre class="programlisting">select dpro as "nombre"
from provincias
</pre>
                             </div>
                        
               </div>
               
                     
               <div class="section" title="5.1.5.2. Comprobaci&oacute;n de nulos">
                  <div class="titlepage">
                     <div>
                        <div>
                           <h4 class="title"><a name="d4e4076"></a>5.1.5.2. Comprobaci&oacute;n de nulos
                           </h4>
                        </div>
                     </div>
                  </div>
                          
                  
                          
                  <p>No usar NVL ni DECODE en oracle ya que no existen en Postgresql
                             ni en Mysql. Mejor usar el case que funciona en todos y es est&aacute;ndar
                             SQL (el coalesce es m&aacute;s parecido al nvl y tambi&eacute;n es est&aacute;ndar, aunque
                             no funciona con oracle 8).
                  </p>
                  
                          
                  <div class="informalexample">
                               
                     
                               <pre class="programlisting">SELECT CASE WHEN cpro is null THEN '-' ELSE cpro END
FROM tcom_usuarios</pre>
                             </div>
                        
               </div>
               
                     
               <div class="section" title="5.1.5.3. Concatenaciones">
                  <div class="titlepage">
                     <div>
                        <div>
                           <h4 class="title"><a name="d4e4081"></a>5.1.5.3. Concatenaciones
                           </h4>
                        </div>
                     </div>
                  </div>
                          
                  
                          
                  <p>Las concatenaciones se hacen con la funci&oacute;n 'concat(str1,str2)'
                             (est&aacute;ndar, en Mysql y oracle ya existe, en postgresql se crea (con el
                             script a continuaci&oacute;n); el operador '||' funcionaba en oracle y
                             postgres aunque no se recomienda).
                  </p>
                  
                          
                  <div class="informalexample">
                               
                     
                               <pre class="programlisting">CREATE OR REPLACE FUNCTION concat(text, text)
  RETURNS text AS
$BODY$
  BEGIN
    RETURN coalesce($1,'') || coalesce($2,'');
  END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE;

GRANT EXECUTE ON FUNCTION concat(text, text) TO public;</pre>
                             </div>
                        
               </div>
                   
            </div>
              
         </div>
         
           
         
           
         
      </div>
      <div class="navfooter">
         <hr>
         <table width="100%" summary="Navigation footer">
            <tr>
               <td width="40%" align="left"><a accesskey="p" href="Parte_3.html">Anterior</a>&nbsp;
               </td>
               <td width="20%" align="center"><a accesskey="u" href="Parte_3.html">Subir</a></td>
               <td width="40%" align="right">&nbsp;<a accesskey="n" href="ch05s02.html">Siguiente</a></td>
            </tr>
            <tr>
               <td width="40%" align="left" valign="top">Parte&nbsp;III.&nbsp;Complementos al desarrollo&nbsp;</td>
               <td width="20%" align="center"><a accesskey="h" href="indice.html">Inicio</a></td>
               <td width="40%" align="right" valign="top">&nbsp;5.2. Web Services</td>
            </tr>
         </table>
      </div>
   </body>
</html>